package id

import (
	"context"
	"fmt"
	"github.com/redis/go-redis/v9"
	"github.com/sony/sonyflake"
	"slices"
	"time"
)

var MachineSlot = 16
var ShardingSlot = 64

var nodes = make([]*sonyflake.Sonyflake, ShardingSlot)

func init() {

	rdb := redis.NewClient(&redis.Options{
		Addr:     "r-uf6kqntxzfrh15p6t1pd.tairpena.rds.aliyuncs.com:6379",
		Password: "cabinet:Yunfeng123",
		DB:       2,
	})

	var ctx = context.Background()

	ip, err := GetFirstPrivateIP()
	if err != nil {
		panic(err)
	}

	var keys []string
	keyPrefix := "MachineID"
	for i := 0; i < MachineSlot; i++ {
		keys = append(keys, fmt.Sprintf("%s:%d", keyPrefix, i))
	}

	results, err := rdb.MGet(ctx, keys...).Result()
	if err != nil {
		panic(err)
	}
	var existMachineIDs []int
	var machineID *int
	for i, val := range results {
		if val == nil {
			continue
		}
		existMachineIDs = append(existMachineIDs, i)
		if ip == val.(string) {
			machineID = &i
			fmt.Println("Found machineID:", *machineID)
		}
	}

	if machineID == nil {
		for i := 0; i < MachineSlot; i++ {
			if slices.Contains(existMachineIDs, i) {
				continue
			}
			err = rdb.SetNX(ctx, fmt.Sprintf("%s:%d", keyPrefix, i), ip, 10*time.Second).Err()
			if err == nil {
				machineID = &i
				fmt.Println("New machineID:", *machineID)
				break
			}
		}
	}

	if machineID == nil {
		panic("no machine ID found")
	}

	go func() {
		for {
			time.Sleep(5 * time.Second)
			expired := rdb.Expire(ctx, fmt.Sprintf("%s:%d", keyPrefix, *machineID), 10*time.Second)
			if expired.Err() != nil {
				panic(expired.Err())
			}
		}
	}()

	//10 位 MachineID = 高 4 位机器 ID（0-15，支持 16 个节点） + 低 6 位基因 ID（0-63，支持 64 个业务 / 分片标识）；
	for i := 0; i < ShardingSlot; i++ {
		flake, err := NewSonyFlakeWithGene(uint8(*machineID), uint8(i))
		if err != nil {
			panic(err)
		}
		nodes[i] = flake
	}
}

func NewSonyFlakeWithGene(machineID uint8, geneID uint8) (*sonyflake.Sonyflake, error) {
	// 校验位数：机器ID≤15（4位），基因ID≤63（6位）
	if machineID > 0x0F || geneID > 0x3F {
		return nil, fmt.Errorf("machineID (0-%d) or geneID (0-%d) out of range", 0x0F, 0x3F)
	}
	// 拼接10位MachineID：高4位机器ID + 低6位基因ID
	combinedID := (uint16(machineID) << 6) | uint16(geneID)

	return sonyflake.New(sonyflake.Settings{
		StartTime: time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC),
		MachineID: func() (uint16, error) {
			return combinedID, nil
		},
	})
}

func main() {
	// 生成ID
	id := GenerateFlakeID(605)
	fmt.Printf("雪花ID：%d\n", id)

	// 解析ID（验证机器ID和基因ID）
	machineID, geneID := DecomposeSlot(id)
	fmt.Printf("解析结果：机器ID=%d，基因ID=%d\n", machineID, geneID)
}

// GenerateUniqueID id1 := 4104066495519
// slot := 2
// a1 := id1 % 1024 % slot
// a2 := id1 % slot
// fmt.Println(a1, a2) slot只要是2的倍数，a1 == a2
func GenerateFlakeID(id int) uint64 {
	uniqueID, err := nodes[id%ShardingSlot].NextID()
	if err != nil {
		panic(err)
	}

	return uniqueID
}

func DecomposeSlot(uniqueID uint64) (machineID, geneID uint8) {
	// 解析ID，获取拼接后的10位combinedID
	parsedID := sonyflake.Decompose(uniqueID)
	combinedID := uint16(parsedID["machine-id"]) // 转换为16位无符号整数

	// 从combinedID中拆分：
	// 高4位是machineID（右移6位，丢弃低6位）
	machineID = uint8(combinedID >> 6)
	// 低6位是geneID（与0x3F按位与，保留低6位）
	geneID = uint8(combinedID & 0x3F)

	return
}
